﻿using HystereticRegularization;
using PGMHelper;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms.DataVisualization.Charting;
using WHelper = PGMHelper.WilsonHelper;

namespace HystereticBasic
{
    /// <summary>
    /// 力位移曲线储存
    /// </summary>
    public class ForceDispObj
    {
        /// <summary>
        /// 力位移曲线数据
        /// </summary>
        protected List<ForceDispBasicPair> DataList { set; get; }

        /// <summary>
        /// 文件路径
        /// </summary>
        protected string FilePath { set; get; }

        #region Porperties

        /// <summary>
        /// 获得力时程曲线
        /// </summary>
        public List<float> Forces
        {
            get
            {
                return (from data in this.DataList select data.Force).ToList();
            }
        }

        /// <summary>
        /// 获得位移时程曲线
        /// </summary>
        public List<float> Disps
        {
            get
            {
                return (from data in this.DataList select data.Disp).ToList();
            }
        }

        /// <summary>
        /// 获得所有序号
        /// </summary>
        public List<int> Orders
        {
            get
            {
                return (from data in this.DataList select data.Order).ToList();
            }
        }

        /// <summary>
        /// 数据点数目
        /// </summary>
        public int Count
        {
            get
            {
                return this.DataList.Count;
            }
        }

        /// <summary>
        /// 重载[]获得力位移对象
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public ForceDispBasicPair this[int index]
        {
            get
            {
                return this.DataList[index];
            }
        }

        /// <summary>
        /// 获得某个序号对应的对象
        /// </summary>
        /// <param name="order"></param>
        /// <returns></returns>
        public bool GetObjByOrder(int order, out ForceDispBasicPair pairObj)
        {
            //实例化
            pairObj = new ForceDispBasicPair();
            //判断序号是否存在
            if (!this.ContainsOrder(order)) return false;
            //遍历对象
            foreach(var obj in this.DataList)
            {
                if (obj.Order == order)
                {
                    pairObj = obj;
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 第一个数据点
        /// </summary>
        public ForceDispBasicPair First()
        {
            return this.DataList.First();
        }

        /// <summary>
        /// 最后一个数据点
        /// </summary>
        public ForceDispBasicPair Last()
        {
            return this.DataList.Last();
        }

        /// <summary>
        /// 位移最大点
        /// </summary>
        public ForceDispBasicPair DispMaxPoint
        {
            get
            {
                return this.DataList.Aggregate((i1, i2) => i1.Disp > i2.Disp ? i1 : i2);
            }
        }

        /// <summary>
        /// 位移最小点
        /// </summary>
        public ForceDispBasicPair DispMinPoint
        {
            get
            {
                return this.DataList.Aggregate((i1, i2) => i1.Disp < i2.Disp ? i1 : i2);
            }
        }

        /// <summary>
        /// 力最大点
        /// </summary>
        public ForceDispBasicPair ForceMaxPoint
        {
            get
            {
                return this.DataList.Aggregate((i1, i2) => i1.Force > i2.Force ? i1 : i2);
            }
        }

        /// <summary>
        /// 力最小点
        /// </summary>
        public ForceDispBasicPair ForceMinPoint
        {
            get
            {
                return this.DataList.Aggregate((i1, i2) => i1.Force < i2.Force ? i1 : i2);
            }
        }

        #endregion

        /// <summary>
        /// 是否单调曲线
        /// </summary>
        /// <returns></returns>
        public bool isMonotonous()
        {
            //数据点过少 不判断单调性
            if (this.Count < 2) return false;
            //数据点恰好为2  满足单调
            if (this.Count == 2) return true;
            //判断单调方向
            bool isACE = this.Last().Disp > this.First().Disp;
            //满足单调的位移增量和不满足单调的位移增量
            float true_dispIncr = 0;
            float false_dispIncr = 0;
            //遍历
            for (int index = 1; index < this.Count - 1; index++)
            {
                //不满足单调的位移增量
                if ((this[index + 1].Disp > this[index].Disp) != isACE)
                    false_dispIncr += Math.Abs(this[index + 1].Disp - this[index].Disp);
                //满足单调的位移增量
                else true_dispIncr += Math.Abs(this[index + 1].Disp - this[index].Disp);
            }
            //超过80%的位移增量满足单调 则 单调满足
            return true_dispIncr == 0 ? false : false_dispIncr / true_dispIncr < 0.2;
        }

        /// <summary>
        /// 计算包围面积
        /// </summary>
        /// <returns></returns>
        public float GetEnergy()
        {
            float A = 0;
            for (int i = 1; i < this.Count; i++)
            {
                A += this[i].GetEnergy(this[i - 1]);
            }
            return A;
        }

        /// <summary>
        /// 是否包含某对象
        /// </summary>
        /// <param name="order"></param>
        /// <returns></returns>
        public bool ContainsOrder(int order)
        {
            return this.Orders.Contains(order);
        }

        /// <summary>
        /// 移除对象
        /// </summary>
        /// <param name="index"></param>
        public void RemoveAt(int index)
        {
            this.DataList.RemoveAt(index);
        }

        #region Data Chart

        /// <summary>
        /// 获得绘图参数
        /// </summary>
        /// <returns></returns>
        public GridViewDatas GetData(string titleName)
        {
            var data = new GridViewDatas("力位移曲线数据");
            data.Add(new GridViewColumn(this.Disps, HystereticHelper.GetDemical(DataType.CyclicDisps),
              titleName + "_变形"));
            data.Add(new GridViewColumn(this.Forces, HystereticHelper.GetDemical(DataType.CyclicForces), 
                titleName + "_力"));
            data.Add(new GridViewColumn(this.Orders, titleName + "_序号"));
            return data;
        }

        /// <summary>
        /// 绘制曲线
        /// </summary>
        /// <param name="chart"></param>
        public void ToChart(Chart chart, string name, int borderWith = -1)
        {
            chart.AddSeries(name, SeriesChartType.Line, borderWith);
            chart.Series[name].Points.DataBindXY(this.Disps, this.Forces);
        }

        /// <summary>
        /// 绘制曲线
        /// </summary>
        /// <param name="chart"></param>
        public void ToChart(Chart chart, string name, Color color, int borderWith, bool isSolid = true)
        {
            chart.AddSeries(name, SeriesChartType.Line, color, borderWith);
            chart.Series[name].Points.DataBindXY(this.Disps, this.Forces);
            chart.Series[name].BorderDashStyle = isSolid ? ChartDashStyle.Solid : ChartDashStyle.Dash;
        }

        /// <summary>
        /// 导出力位移数据
        /// </summary>
        public void ToTXT()
        {
            var filePath = string.Empty;
            if (!WilsonHelper.SelectSaveFilePath("文本文件|*.txt|所有文件类型|*.*", "力位移曲线", ref filePath))
                return;
            this.ToTXT(filePath);
        }

        /// <summary>
        /// 导出力位移数据
        /// </summary>
        public void ToTXT(string filePath, string delimiter = " ")
        {
            //初始化
            var str = string.Empty;
            //遍历数据
            this.DataList.ForEach(data =>
            {
                str += string.Format("{0}{1}{2}", data.Disp, delimiter, data.Force);
                str += Environment.NewLine;
            });
            //写出数据
            File.WriteAllText(filePath, str);
        }

        #endregion

        #region Add

        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="originalcurve"></param>
        public void AddRange(List<ForceDispBasicPair> pairList)
        {
            this.DataList.AddRange(pairList);
        }

        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="obj"></param>
        public void AddRange(ForceDispObj obj)
        {
            this.AddRange(obj.DataList);
        }

        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="pair"></param>
        public void Add(ForceDispBasicPair pair)
        {
            this.DataList.Add(pair);
        }

        /// <summary>
        /// 插入对象
        /// </summary>
        /// <param name="index"></param>
        /// <param name="pair"></param>
        public void Insert(int index, ForceDispBasicPair pair)
        {
            this.DataList.Insert(index, pair);
        }

        #endregion

        /// <summary>
        /// 转为列表
        /// </summary>
        /// <returns></returns>
        public List<ForceDispBasicPair> ToList()
        {
            return this.DataList;
        }

        /// <summary>
        /// 设定力位移数据
        /// </summary>
        /// <param name="forceDispList"></param>
        public void SetForceDispList(List<ForceDispBasicPair> forceDispList)
        {
            this.DataList = forceDispList;
        }

        /// <summary>
        /// 获得放大后对象
        /// </summary>
        /// <param name="defromMultiplier"></param>
        /// <param name="forceMultiplier"></param>
        /// <returns></returns>
        public ForceDispObj GetAmplitudeObj(float defromMultiplier, float forceMultiplier)
        {
            //初始化
            var obj = new ForceDispObj();
            //遍历数据
            this.DataList.ForEach(data => obj.Add(data.GetAmplitudeObj(defromMultiplier, forceMultiplier)));
            //返回对象
            return obj;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        public ForceDispObj()
        {
            this.DataList = new List<HystereticBasic.ForceDispBasicPair>();
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="originalcurve"></param>
        public ForceDispObj(List<ForceDispBasicPair> pairList) : this()
        {
            this.DataList.AddRange(pairList);
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="filePath"></param>
        public ForceDispObj(string filePath, int skipLine) : this()
        {
            //获得文件路径
            this.FilePath = filePath;
            //读取整个文件
            var fileList = File.ReadAllLines(filePath).ToList();
            //初始化
            float disp, force;
            //跳过目标行
            for (int index = skipLine; index < fileList.Count; index++)
            {
                //拆分字符串
                var strList = WHelper.SplitStr(fileList[index]);
                //数据是否充足
                if (strList.Count != 2) continue;
                //判断是否可以转换
                if (!float.TryParse(strList[0], out disp) ||
                    !float.TryParse(strList[1], out force))
                    continue;
                this.Add(new ForceDispBasicPair(this.Count, disp, force));
            }
        }

        /// <summary>
        /// 复制对象
        /// 仅复制力和位移
        /// </summary>
        /// <param name="obj"></param>
        public ForceDispObj(ForceDispObj obj) : this()
        {
            obj.DataList.ForEach(dispObj => this.Add(new ForceDispBasicPair(dispObj)));
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dispList"></param>
        /// <param name="forceList"></param>
        public ForceDispObj(List<float> dispList, List<float> forceList): this()
        {
            for (int i = 0; i < Math.Min(dispList.Count, forceList.Count); i++)
                this.DataList.Add(new ForceDispBasicPair(i, dispList[i], forceList[i]));
        }
    }
}
